﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Win.CSkin.Test.Data
{
    public class SqlDataReaderTools
    {
        private SqlConnection cn;
        private SqlTransaction tran;
        /// <summary>
        /// 方法1：根据配置创建1个连接，并打开
        /// </summary>
        /// <param name="dataBaseName"></param>
        /// <returns></returns>
        public SqlConnection CreateConAndOpen(string dataBaseName)
        {
            cn = new SqlConnection();
            cn.ConnectionString = ConfigurationManager.ConnectionStrings[dataBaseName].ConnectionString;
            cn.Open();
            return cn;
        }
        /// <summary>
        /// 方法2：根据配置仅创建1个连接
        /// </summary>
        /// <param name="dataBaseName"></param>
        /// <returns></returns>
        public SqlConnection CreateCon(string dataBaseName)
        {

            cn = new SqlConnection();
            cn.ConnectionString = ConfigurationManager.ConnectionStrings[dataBaseName].ConnectionString;
            return cn;
        }
        /// <summary>
        /// 方法3：创建一个开始事务的连接
        /// </summary>
        /// <param name="dataBaseName"></param>
        /// <returns></returns>
        public SqlConnection CreateConAndOpenTran(string dataBaseName)
        {

            cn = new SqlConnection();
            cn.ConnectionString = ConfigurationManager.ConnectionStrings[dataBaseName].ConnectionString;
            cn.Open();
            tran = cn.BeginTransaction();
            return cn;
        }
        /// <summary>
        /// 方法4：打开该连接
        /// </summary>
        public void OpenCon()
        {
            cn.Open();
        }
        /// <summary>
        /// 方法5：关闭该连接
        /// </summary>
        public void CloseCon()
        {
            cn.Close();
        }
        /// <summary>
        /// 方法6：关闭连接并提交事务
        /// </summary>
        public void CloseConAndCommitTran()
        {
            tran.Commit();
            cn.Close();
        }
        /// <summary>
        /// 方法7：关闭连接回滚事务
        /// </summary>
        public void CloseConAndRollbackTran()
        {
            tran.Rollback();
            cn.Close();
        }
        /// <summary>
        /// 方法8：销毁连接提交事务
        /// </summary>
        public void DisposeCon()
        {
            cn.Dispose();
        }
        public void DisposeConAndCommitTran()
        {
            tran.Commit();
            cn.Dispose();
        }
        /// <summary>
        /// 方法9销毁连接回滚事务
        /// </summary>
        public void DisposeConAndRollbackTran()
        {
            tran.Rollback();
            cn.Dispose();
        }
        /// <summary>
        /// 方法10：执行sql查询(不开始事务)
        /// </summary>
        /// <param name="sql"></param>
        /// <returns>返回SqlDataReader</returns>
        public SqlDataReader ExecuteReader(string sql)
        {
            SqlDataReader dr;
            using (SqlCommand cmd = new SqlCommand())
            {
                cmd.Connection = cn;
                cmd.CommandText = sql;
                dr = cmd.ExecuteReader();
            }
            return dr;
        }

        /// <summary>
        /// 方法11：判断SqlDataReader是否存在某列
        /// </summary>
        /// <param name="dr">SqlDataReader</param>
        /// <param name="columnName">列名</param>
        /// <returns></returns>
        private bool readerExists(SqlDataReader dr, string columnName)
        {

            dr.GetSchemaTable().DefaultView.RowFilter = "ColumnName= '" + columnName + "'";

            return (dr.GetSchemaTable().DefaultView.Count > 0);

        }

        ///<summary>
        ///方法12：利用反射和泛型将SqlDataReader转换成List模型
        ///</summary>
        ///<param name="sql">查询sql语句</param>
        ///<returns></returns>

        public IList<T> ExecuteToList<T>(string sql) where T : new()

        {
            IList<T> list;

            Type type = typeof(T);

            string tempName = string.Empty;

            using (SqlDataReader reader = ExecuteReader(sql))
            {
                if (reader.HasRows)
                {
                    list = new List<T>();
                    while (reader.Read())
                    {
                        T t = new T();

                        PropertyInfo[] propertys = t.GetType().GetProperties();

                        foreach (PropertyInfo pi in propertys)
                        {
                            tempName = pi.Name;

                            if (readerExists(reader, tempName))
                            {
                                if (!pi.CanWrite)
                                {
                                    continue;
                                }
                                var value = reader[tempName];

                                if (value != DBNull.Value)
                                {
                                    pi.SetValue(t, value, null);
                                }

                            }

                        }

                        list.Add(t);

                    }
                    return list;
                }
            }
            return null;
        }

        /// <summary>
        /// 方法13：批量往表插入数据（不使用始事务）
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="connection">ConfigurationManager.ConnectionStrings["BPMDATA"].ConnectionString</param>
        /// <param name="tableName"></param>
        /// <param name="list">插入数据的List集合</param>
        /// <returns></returns>
        public string BulkInsert<T>(string connection, string tableName, IList<T> list)
        {
            try
            {
                using (var bulkCopy = new SqlBulkCopy(connection))
                {
                    bulkCopy.BatchSize = list.Count;
                    bulkCopy.DestinationTableName = tableName;

                    var table = new DataTable();
                    var props = TypeDescriptor.GetProperties(typeof(T))
                                               .Cast<PropertyDescriptor>()
                                               .Where(propertyInfo => propertyInfo.PropertyType != null
                                                    && propertyInfo.PropertyType.Namespace != null
                                                    && propertyInfo.PropertyType.Namespace.Equals("System"))
                                               .ToArray();

                    foreach (var propertyInfo in props)
                    {
                        System.Diagnostics.Debug.WriteLine("列:" + propertyInfo.Name);
                        bulkCopy.ColumnMappings.Add(propertyInfo.Name, propertyInfo.Name);
                        table.Columns.Add(propertyInfo.Name, Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType);
                    }

                    var values = new object[props.Length];
                    foreach (var item in list)
                    {
                        for (var i = 0; i < values.Length; i++)
                        {
                            values[i] = props[i].GetValue(item);
                        }

                        table.Rows.Add(values);
                    }

                    bulkCopy.WriteToServer(table);
                }
                return "ok";
            }
            catch (Exception ee)
            {
                return ee.Message;
            }
        }

        /// <summary>
        ///方法14：批量往表插入数据（使用事务）
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="connection">ConfigurationManager.ConnectionStrings["BPMDATA"].ConnectionString</param>
        /// <param name="tableName"></param>
        /// <param name="list"></param>
        /// <returns></returns>
        public void BulkInsertTran<T>(string tableName, IList<T> list)
        {
            using (var bulkCopy = new SqlBulkCopy(cn, SqlBulkCopyOptions.Default, tran))
            {
                bulkCopy.BatchSize = list.Count;
                bulkCopy.DestinationTableName = tableName;

                var table = new DataTable();
                var props = TypeDescriptor.GetProperties(typeof(T))
                                           .Cast<PropertyDescriptor>()
                                           .Where(propertyInfo => propertyInfo.PropertyType != null
                                                && propertyInfo.PropertyType.Namespace != null
                                                && propertyInfo.PropertyType.Namespace.Equals("System"))
                                           .ToArray();

                foreach (var propertyInfo in props)
                {
                    System.Diagnostics.Debug.WriteLine("列:" + propertyInfo.Name);
                    bulkCopy.ColumnMappings.Add(propertyInfo.Name, propertyInfo.Name);
                    table.Columns.Add(propertyInfo.Name, Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType);
                }

                var values = new object[props.Length];
                foreach (var item in list)
                {
                    for (var i = 0; i < values.Length; i++)
                    {
                        values[i] = props[i].GetValue(item);
                    }

                    table.Rows.Add(values);
                }

                bulkCopy.WriteToServer(table);
            }
        }
        /// <summary>
        /// 方法15：执行无返回值的操作（delete,insert,update）,使用事务
        /// </summary>
        /// <param name="sql"></param>
        public void ExecuteNonQueryTran(string sql)
        {

            SqlCommand cmd = new SqlCommand();
            cmd.Connection = cn;
            cmd.CommandText = sql;
            cmd.Transaction = tran;
            cmd.ExecuteNonQuery();

        }

    }
}
